/*=========================================================================
*
*  Copyright NumFOCUS
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0.txt
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*=========================================================================*/
/*
 * WARNING: DO NOT EDIT THIS FILE!
 * THIS FILE IS AUTOMATICALLY GENERATED BY THE SIMPLEITK BUILD PROCESS.
 * Please look at sitkImageFilterTemplate.cxx.in to make changes.
 */

#include "itkImage.h"
#include "itkVectorImage.h"
#include "itkLabelMap.h"
#include "itkLabelObject.h"
#include "itkNumericTraits.h"
#include "itkNumericTraitsVariableLengthVectorPixel.h"
#include "itkVectorIndexSelectionCastImageFilter.h"
#include "itkComposeImageFilter.h"

#include "sitkPasteImageFilter.h"
#include "itkNPasteImageFilter.h"

#include "sitkToPixelType.hxx"



namespace itk {
namespace simple {

//-----------------------------------------------------------------------------

//
// Default constructor that initializes parameters
//
PasteImageFilter::PasteImageFilter ()
{
  this->m_MemberFactory.reset( new detail::MemberFunctionFactory<MemberFunctionType>( this ) );

  this->m_MemberFactory->RegisterMemberFunctions< PixelIDTypeList, 2, SITK_MAX_DIMENSION > ();

  this->m_MemberFactory2.reset( new detail::MemberFunctionFactory<MemberFunction2Type>( this ) );
  this->m_MemberFactory2->RegisterMemberFunctions< PixelIDTypeList, 2, SITK_MAX_DIMENSION > ();


}

//
// Destructor
//
PasteImageFilter::~PasteImageFilter() = default;



//
// ToString
//
std::string PasteImageFilter::ToString() const
{
  std::ostringstream out;
  out << "itk::simple::PasteImageFilter\n";
  out << "  SourceSize: ";
  this->ToStringHelper(out, this->m_SourceSize);
  out << std::endl;
  out << "  SourceIndex: ";
  this->ToStringHelper(out, this->m_SourceIndex);
  out << std::endl;
  out << "  DestinationIndex: ";
  this->ToStringHelper(out, this->m_DestinationIndex);
  out << std::endl;
  out << "  DestinationSkipAxes: ";
  this->ToStringHelper(out, this->m_DestinationSkipAxes);
  out << std::endl;

  out << ProcessObject::ToString();
  return out.str();
}

//
// Execute
//
Image PasteImageFilter::Execute ( const Image & destinationImage, const Image & sourceImage )
{
  const PixelIDValueEnum type = destinationImage.GetPixelID();
  const unsigned int dimension = destinationImage.GetDimension();
  CheckImageMatchingPixelType(  destinationImage, sourceImage, "sourceImage" );

  return this->m_MemberFactory->GetMemberFunction( type, dimension )( &destinationImage, &sourceImage );
}
Image PasteImageFilter::Execute ( const Image & destinationImage, double constant )
{
  const PixelIDValueEnum type = destinationImage.GetPixelID();
  const unsigned int dimension = destinationImage.GetDimension();

  return this->m_MemberFactory2->GetMemberFunction( type, dimension )( &destinationImage, constant );
}
Image PasteImageFilter::Execute ( Image && destinationImage, const Image & sourceImage )
{
  Image &temp = destinationImage;
  auto autoResetInPlace = make_scope_exit([this, &temp]{this->m_InPlace=false; Image moved(std::move(temp));});
  if (temp.IsUnique())
  {
    m_InPlace = true;
  }
  return this->Execute( destinationImage, sourceImage );
}
Image PasteImageFilter::Execute ( Image && destinationImage, double constant )
{
  Image &temp = destinationImage;
  auto autoResetInPlace = make_scope_exit([this, &temp]{this->m_InPlace=false; Image moved(std::move(temp));});
  if (temp.IsUnique())
  {
    m_InPlace = true;
  }
  return this->Execute( destinationImage, constant );
}

//-----------------------------------------------------------------------------

//
// Custom Casts
//
namespace {

}

//-----------------------------------------------------------------------------

sitkClangDiagnosticPush();
sitkClangWarningIgnore("-Wunused-local-typedef");

//
// ExecuteInternal
//
template <class TImageType>
Image PasteImageFilter::ExecuteInternal ( const Image * inDestinationImage, const Image * inSourceImage )
{
  assert( inDestinationImage != nullptr );
  assert( inSourceImage != nullptr );


  // Define the input and output image types
  using InputImageType = TImageType;


  // Get the pointer to the ITK image contained in image1
  typename InputImageType::ConstPointer destinationImage = this->CastImageToITK<InputImageType>( *inDestinationImage );

  return this->ExecuteInternal<TImageType>(destinationImage, inSourceImage,
                                           std::integral_constant<unsigned int, TImageType::ImageDimension>());
}

template <class TImageType, unsigned int SourceDimension>
Image PasteImageFilter::ExecuteInternal(
    const TImageType *destinationImage, const Image *inSourceImage,
    std::integral_constant<unsigned int, SourceDimension> )
{
  if (inSourceImage->GetDimension() != SourceDimension)
  {
    return this->ExecuteInternal(
        destinationImage, inSourceImage, std::integral_constant< unsigned int, SourceDimension -1>());
  }

  // Define the input and output image types
  using InputImageType = TImageType;
  using SourceImageType =  typename InputImageType::template RebindImageType<typename InputImageType::PixelType, SourceDimension>;

  using SourceIndexType = typename SourceImageType::IndexType;
  using SourceSizeType = typename SourceImageType::SizeType;

  using OutputImageType = InputImageType;

  using FilterType = itk::NPasteImageFilter< InputImageType, SourceImageType, OutputImageType >;
  // Set up the ITK filter
  typename FilterType::Pointer filter = FilterType::New();


  assert( destinationImage != nullptr );
  filter->SetInput( destinationImage );
  assert( inSourceImage != nullptr );
  filter->SetSourceImage( this->CastImageToITK<typename FilterType::SourceImageType>(*inSourceImage) );

  typename SourceImageType::RegionType itkRegion(
      sitkSTLVectorToITK<SourceIndexType>(m_SourceIndex),
      sitkSTLVectorToITK<SourceSizeType>(m_SourceSize));

  filter->SetSourceRegion( itkRegion );
  typename InputImageType::IndexType itkVecDestinationIndex = sitkSTLVectorToITK<typename InputImageType::IndexType>( this->GetDestinationIndex() );
  filter->SetDestinationIndex( itkVecDestinationIndex );
  if (!m_DestinationSkipAxes.empty())
  {
    filter->SetDestinationSkipAxes(sitkSTLVectorToITK< typename FilterType::InputSkipAxesArrayType>(m_DestinationSkipAxes));
  }
  filter->SetInPlace( m_InPlace );




  this->PreUpdate( filter.GetPointer() );



  // Run the ITK filter and return the output as a SimpleITK image
  filter->Update();

  typename FilterType::OutputImageType::Pointer itkOutImage{ filter->GetOutput()};
  filter = nullptr;
  this->FixNonZeroIndex( itkOutImage.GetPointer() );
  return Image{ this->CastITKToImage( itkOutImage.GetPointer() ) };
}

template <class TImageType>
Image PasteImageFilter::ExecuteInternal ( const TImageType *,
                                          const Image * sourceImage,
                                          std::integral_constant<unsigned int, 1> )
{
  sitkExceptionMacro("Unable to use the sourceImage of dimension" << sourceImage->GetDimension()
                                                                  << " with destination dimension of " << TImageType::ImageDimension << ".");
}

template <class TImageType>
Image PasteImageFilter::ExecuteInternal ( const Image * inDestinationImage, double constant )
{
  // Define the input and output image types
  using InputImageType = TImageType;
  using SourceImageType =  InputImageType;

  using SourceIndexType = typename SourceImageType::IndexType;
  using SourceSizeType = typename SourceImageType::SizeType;

  using OutputImageType = InputImageType;


  using FilterType = itk::NPasteImageFilter< InputImageType, SourceImageType, OutputImageType >;
  // Set up the ITK filter
  typename FilterType::Pointer filter = FilterType::New();


  // Get the pointer to the ITK image contained in image1
  typename InputImageType::ConstPointer destinationImage = this->CastImageToITK<InputImageType>( *inDestinationImage );
  assert( destinationImage != nullptr );
  filter->SetInput( destinationImage );

  typename SourceImageType::PixelType c;
  NumericTraits<typename SourceImageType::PixelType>::SetLength( c, destinationImage->GetNumberOfComponentsPerPixel() );
  ToPixelType( constant, c );
  filter->SetConstant(c);

  typename SourceImageType::RegionType itkRegion(
      sitkSTLVectorToITK<SourceIndexType>(m_SourceIndex),
      sitkSTLVectorToITK<SourceSizeType>(m_SourceSize));

  filter->SetSourceRegion( itkRegion );
  typename InputImageType::IndexType itkVecDestinationIndex = sitkSTLVectorToITK<typename InputImageType::IndexType>( this->GetDestinationIndex() );
  filter->SetDestinationIndex( itkVecDestinationIndex );
  if (!m_DestinationSkipAxes.empty())
  {
    filter->SetDestinationSkipAxes(sitkSTLVectorToITK< typename FilterType::InputSkipAxesArrayType>(m_DestinationSkipAxes));
  }
  filter->SetInPlace( m_InPlace );




  this->PreUpdate( filter.GetPointer() );



  // Run the ITK filter and return the output as a SimpleITK image
  filter->Update();

  typename FilterType::OutputImageType::Pointer itkOutImage{ filter->GetOutput()};
  filter = nullptr;
  this->FixNonZeroIndex( itkOutImage.GetPointer() );
  return Image{ this->CastITKToImage( itkOutImage.GetPointer() ) };
}

sitkClangDiagnosticPop();

//-----------------------------------------------------------------------------


//
// Function to run the Execute method of this filter
//
Image Paste ( const Image & destinationImage, const Image & sourceImage, std::vector<unsigned int> sourceSize, std::vector<int> sourceIndex, std::vector<int> destinationIndex, std::vector<bool> destinationSkipAxes )
{
  PasteImageFilter filter;
  filter.SetSourceSize( sourceSize );
  filter.SetSourceIndex( sourceIndex );
  filter.SetDestinationIndex( destinationIndex );
  filter.SetDestinationSkipAxes( std::move(destinationSkipAxes) );
  return filter.Execute ( destinationImage, sourceImage );
}
//
// Function to run the Execute method of this filter
//
Image Paste ( Image && destinationImage, const Image & sourceImage, std::vector<unsigned int> sourceSize, std::vector<int> sourceIndex, std::vector<int> destinationIndex, std::vector<bool> destinationSkipAxes )
{
  PasteImageFilter filter;
  filter.SetSourceSize( std::move(sourceSize) );
  filter.SetSourceIndex( std::move(sourceIndex) );
  filter.SetDestinationIndex( std::move(destinationIndex) );
  filter.SetDestinationSkipAxes( std::move(destinationSkipAxes) );
  return filter.Execute ( std::move(destinationImage), sourceImage );
}

} // end namespace simple
} // end namespace itk
